/*
colpick Color Picker / colpick.com
Copyright 2013 Jose Vargas. Licensed under GPL license.

	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Based on Stefan Petre's Color Picker www.eyecon.ro, dual licensed under the MIT and GPL licenses
 */

(function ($) {
  var colpick = (function () {
    var
      tpl = '<div class="colpick"><div class="colpick_color"><div><div></div></div></div><div class="colpick_hue"><div></div></div><div class="colpick_new_color"></div><div class="colpick_current_color"></div><div class="colpick_hex_field"><div>#</div><input type="text" maxlength="6" size="6" /></div><div class="colpick_rgb_r colpick_field"><div>R</div><input type="text" maxlength="3" size="3" /><span></span></div><div class="colpick_rgb_g colpick_field"><div>G</div><input type="text" maxlength="3" size="3" /><span></span></div><div class="colpick_rgb_b colpick_field"><div>B</div><input type="text" maxlength="3" size="3" /><span></span></div><div class="colpick_hsb_h colpick_field"><div>H</div><input type="text" maxlength="3" size="3" /><span></span></div><div class="colpick_hsb_s colpick_field"><div>S</div><input type="text" maxlength="3" size="3" /><span></span></div><div class="colpick_hsb_b colpick_field"><div>B</div><input type="text" maxlength="3" size="3" /><span></span></div><div class="colpick_submit"></div></div>'
    var defaults = {
      showEvent: 'click',
      onShow: function () {},
      onBeforeShow: function () {},
      onHide: function () {},
      onChange: function () {},
      onSubmit: function () {},
      colorScheme: 'light',
      color: '11ff00',
      livePreview: true,
      flat: false,
      layout: 'full',
      submit: 1,
      submitText: 'OK',
      height: 150
    }
    // Fill the inputs of the plugin
    var fillRGBFields = function (hsb, cal) {
      var rgb = HSBToRGB(hsb)
      $(cal).data('colpick').fields
        .eq(1).val(rgb.r).end()
        .eq(2).val(rgb.g).end()
        .eq(3).val(rgb.b).end()
    }
    var fillHSBFields = function (hsb, cal) {
      $(cal).data('colpick').fields
        .eq(4).val(Math.round(hsb.h * 10) / 10).end()
        .eq(5).val(Math.round(hsb.s * 10) / 10).end()
        .eq(6).val(Math.round(hsb.b * 10) / 10).end()
    }
    var fillHexFields = function (hsb, cal) {
      $(cal).data('colpick').fields.eq(0).val(HSBToHex(hsb))
    }
    // Set the round selector position
    var setSelector = function (hsb, cal) {
      $(cal).data('colpick').selector.css('backgroundColor', '#' + HSBToHex({ h: hsb.h, s: 100, b: 100 }))
      $(cal).data('colpick').selectorIndic.css({
        left: parseInt($(cal).data('colpick').height * hsb.s / 100, 10),
        top: parseInt($(cal).data('colpick').height * (100 - hsb.b) / 100, 10)
      })
    }
    // Set the hue selector position
    var setHue = function (hsb, cal) {
      $(cal).data('colpick').hue.css('top', parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h / 360, 10))
    }
    // Set current and new colors
    var setCurrentColor = function (hsb, cal) {
      $(cal).data('colpick').currentColor.css('backgroundColor', '#' + HSBToHex(hsb))
    }
    var setNewColor = function (hsb, cal) {
      $(cal).data('colpick').newColor.css('backgroundColor', '#' + HSBToHex(hsb))
    }
    // Function called when the new color is changed
    var change = function (ev) {
      var cal = $(this).parent().parent(); var col
      if (this.parentNode.className.indexOf('_hex') > 0) {
        cal.data('colpick').color = col = HexToHSB(fixHex(this.value))
      } else if (this.parentNode.className.indexOf('_hsb') > 0) {
        cal.data('colpick').color = col = fixHSB({
          h: parseInt(cal.data('colpick').fields.eq(4).val(), 10),
          s: parseInt(cal.data('colpick').fields.eq(5).val(), 10),
          b: parseInt(cal.data('colpick').fields.eq(6).val(), 10)
        })
      } else {
        cal.data('colpick').color = col = RGBToHSB(fixRGB({
          r: parseInt(cal.data('colpick').fields.eq(1).val(), 10),
          g: parseInt(cal.data('colpick').fields.eq(2).val(), 10),
          b: parseInt(cal.data('colpick').fields.eq(3).val(), 10)
        }))
      }
      if (ev) {
        fillRGBFields(col, cal.get(0))
        fillHexFields(col, cal.get(0))
        fillHSBFields(col, cal.get(0))
      }
      setSelector(col, cal.get(0))
      setHue(col, cal.get(0))
      setNewColor(col, cal.get(0))
      cal.data('colpick').onChange.apply(cal.parent(), [col, HSBToHex(col), HSBToRGB(col)])
    }
    // Change style on blur and focus of inputs
    var blur = function (ev) {
      $(this).parent().removeClass('colpick_focus')
    }
    var focus = function () {
      $(this).parent().parent().data('colpick').fields.parent().removeClass('colpick_focus')
      $(this).parent().addClass('colpick_focus')
    }
    // Increment/decrement arrows next to the fields
    var downIncrement = function (ev) {
      var field = $(this).parent().find('input').focus()
      var current = {
        el: $(this).parent().addClass('colpick_slider'),
        max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
        y: ev.pageY,
        field: field,
        val: parseInt(field.val(), 10),
        preview: $(this).parent().parent().data('colpick').livePreview
      }
      $(document).mouseup(current, upIncrement)
      $(document).mousemove(current, moveIncrement)
    }
    var moveIncrement = function (ev) {
      ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val - ev.pageY + ev.data.y, 10))))
      if (ev.data.preview) {
        change.apply(ev.data.field.get(0), [true])
      }
      return false
    }
    var upIncrement = function (ev) {
      change.apply(ev.data.field.get(0), [true])
      ev.data.el.removeClass('colpick_slider').find('input').focus()
      $(document).off('mouseup', upIncrement)
      $(document).off('mousemove', moveIncrement)
      return false
    }
    // Hue slider functions
    var downHue = function (ev) {
      var current = {
        cal: $(this).parent(),
        y: $(this).offset().top
      }
      current.preview = current.cal.data('colpick').livePreview
      $(document).mouseup(current, upHue)
      $(document).mousemove(current, moveHue)

      change.apply(
        current.cal.data('colpick')
          .fields.eq(4).val(parseInt(360 * (current.cal.data('colpick').height - (ev.pageY - current.y)) / current.cal.data('colpick').height, 10))
          .get(0),
        [current.preview]
      )
    }
    var moveHue = function (ev) {
      change.apply(
        ev.data.cal.data('colpick')
          .fields.eq(4).val(parseInt(360 * (ev.data.cal.data('colpick').height - Math.max(0, Math.min(ev.data.cal.data('colpick').height, (ev.pageY - ev.data.y)))) / ev.data.cal.data('colpick').height, 10))
          .get(0),
        [ev.data.preview]
      )
      return false
    }
    var upHue = function (ev) {
      fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0))
      fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0))
      $(document).off('mouseup', upHue)
      $(document).off('mousemove', moveHue)
      return false
    }
    // Color selector functions
    var downSelector = function (ev) {
      ev.preventDefault ? ev.preventDefault() : ev.returnValue = false
      // Get colpick and position of the selector
      var current = {
        cal: $(this).parent(),
        pos: $(this).offset()
      }
      current.preview = current.cal.data('colpick').livePreview

      $(document).mouseup(current, upSelector)
      $(document).mousemove(current, moveSelector)

      change.apply(
        current.cal.data('colpick').fields
          .eq(6).val(parseInt(100 * (current.cal.data('colpick').height - (ev.pageY - current.pos.top)) / current.cal.data('colpick').height, 10)).end()
          .eq(5).val(parseInt(100 * (ev.pageX - current.pos.left) / current.cal.data('colpick').height, 10))
          .get(0),
        [current.preview]
      )
    }
    var moveSelector = function (ev) {
      change.apply(
        ev.data.cal.data('colpick').fields
          .eq(6).val(parseInt(100 * (ev.data.cal.data('colpick').height - Math.max(0, Math.min(ev.data.cal.data('colpick').height, (ev.pageY - ev.data.pos.top)))) / ev.data.cal.data('colpick').height, 10)).end()
          .eq(5).val(parseInt(100 * (Math.max(0, Math.min(ev.data.cal.data('colpick').height, (ev.pageX - ev.data.pos.left)))) / ev.data.cal.data('colpick').height, 10))
          .get(0),
        [ev.data.preview]
      )
      return false
    }
    var upSelector = function (ev) {
      fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0))
      fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0))
      $(document).off('mouseup', upSelector)
      $(document).off('mousemove', moveSelector)
      return false
    }
    // Submit button
    var clickSubmit = function (ev) {
      var cal = $(this).parent()
      var col = cal.data('colpick').color
      cal.data('colpick').origColor = col
      setCurrentColor(col, cal.get(0))
      cal.data('colpick').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colpick').el)
    }
    // Show/hide the color picker
    var show = function (ev) {
      var cal = $('#' + $(this).data('colpickId'))
      cal.data('colpick').onBeforeShow.apply(this, [cal.get(0)])
      var pos = $(this).offset()
      var top = pos.top + this.offsetHeight
      var left = pos.left
      var viewPort = getViewport()
      if (left + 346 > viewPort.l + viewPort.w) {
        left -= 346
      }
      cal.css({ left: left + 'px', top: top + 'px' })
      if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) != false) {
        cal.show()
      }
      // Hide when user clicks outside
      $('html').mousedown({ cal: cal }, hide)
      cal.mousedown(function (ev) { ev.stopPropagation() })
      return false
    }
    var hide = function (ev) {
      if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
        ev.data.cal.hide()
      }
      $('html').off('mousedown', hide)
      return false
    }
    var getViewport = function () {
      var m = document.compatMode == 'CSS1Compat'
      return {
        l: window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
        w: window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth)
      }
    }
    // Fix the values if the user enters a negative or high value
    var fixHSB = function (hsb) {
      return {
        h: Math.min(360, Math.max(0, hsb.h)),
        s: Math.min(100, Math.max(0, hsb.s)),
        b: Math.min(100, Math.max(0, hsb.b))
      }
    }
    var fixRGB = function (rgb) {
      return {
        r: Math.min(255, Math.max(0, rgb.r)),
        g: Math.min(255, Math.max(0, rgb.g)),
        b: Math.min(255, Math.max(0, rgb.b))
      }
    }
    var fixHex = function (hex) {
      var len = 6 - hex.length
      if (len > 0) {
        var o = []
        for (var i = 0; i < len; i++) {
          o.push('0')
        }
        o.push(hex)
        hex = o.join('')
      }
      return hex
    }
    // Color space convertion
    var HexToRGB = function (hex) {
      var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16)
      return { r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF) }
    }
    var HexToHSB = function (hex) {
      return RGBToHSB(HexToRGB(hex))
    }
    var RGBToHSB = function (rgb) {
      var hsb = {
        h: 0,
        s: 0,
        b: 0
      }
      var min = Math.min(rgb.r, rgb.g, rgb.b)
      var max = Math.max(rgb.r, rgb.g, rgb.b)
      var delta = max - min
      hsb.b = max
      if (max != 0) {

      }
      hsb.s = max != 0 ? 255 * delta / max : 0
      if (hsb.s != 0) {
        if (rgb.r == max) {
          hsb.h = (rgb.g - rgb.b) / delta
        } else if (rgb.g == max) {
          hsb.h = 2 + (rgb.b - rgb.r) / delta
        } else {
          hsb.h = 4 + (rgb.r - rgb.g) / delta
        }
      } else {
        hsb.h = -1
      }
      hsb.h *= 60
      if (hsb.h < 0) {
        hsb.h += 360
      }
      hsb.s *= 100 / 255
      hsb.b *= 100 / 255
      return hsb
    }
    var HSBToRGB = function (hsb) {
      var rgb = {}
      var h = Math.round(hsb.h)
      var s = Math.round(hsb.s * 255 / 100)
      var v = Math.round(hsb.b * 255 / 100)
      if (s == 0) {
        rgb.r = rgb.g = rgb.b = v
      } else {
        var t1 = v
        var t2 = (255 - s) * v / 255
        var t3 = (t1 - t2) * (h % 60) / 60
        if (h == 360) h = 0
        if (h < 60) { rgb.r = t1;	rgb.b = t2; rgb.g = t2 + t3 } else if (h < 120) { rgb.g = t1; rgb.b = t2;	rgb.r = t1 - t3 } else if (h < 180) { rgb.g = t1; rgb.r = t2;	rgb.b = t2 + t3 } else if (h < 240) { rgb.b = t1; rgb.r = t2;	rgb.g = t1 - t3 } else if (h < 300) { rgb.b = t1; rgb.g = t2;	rgb.r = t2 + t3 } else if (h < 360) { rgb.r = t1; rgb.g = t2;	rgb.b = t1 - t3 } else { rgb.r = 0; rgb.g = 0;	rgb.b = 0 }
      }
      return { r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b) }
    }
    var RGBToHex = function (rgb) {
      var hex = [
        rgb.r.toString(16),
        rgb.g.toString(16),
        rgb.b.toString(16)
      ]
      $.each(hex, function (nr, val) {
        if (val.length == 1) {
          hex[nr] = '0' + val
        }
      })
      return hex.join('')
    }
    var HSBToHex = function (hsb) {
      return RGBToHex(HSBToRGB(hsb))
    }
    var restoreOriginal = function () {
      var cal = $(this).parent()
      var col = cal.data('colpick').origColor
      cal.data('colpick').color = col
      fillRGBFields(col, cal.get(0))
      fillHexFields(col, cal.get(0))
      fillHSBFields(col, cal.get(0))
      setSelector(col, cal.get(0))
      setHue(col, cal.get(0))
      setNewColor(col, cal.get(0))
    }
    return {
      init: function (opt) {
        opt = $.extend({}, defaults, opt || {})
        // Set color
        if (typeof opt.color === 'string') {
          opt.color = HexToHSB(opt.color)
        } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
          opt.color = RGBToHSB(opt.color)
        } else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
          opt.color = fixHSB(opt.color)
        } else {
          return this
        }

        // For each selected DOM element
        return this.each(function () {
          // If the element does not have an ID
          if (!$(this).data('colpickId')) {
            var options = $.extend({}, opt)
            options.origColor = opt.color
            // Generate and assign a random ID
            var id = 'collorpicker_' + parseInt(Math.random() * 1000)
            $(this).data('colpickId', id)
            // Set the tpl's ID and get the HTML
            var cal = $(tpl).attr('id', id)
            // Add class according to layout
            cal.addClass('colpick_' + options.layout + (options.submit ? '' : ' colpick_' + options.layout + '_ns'))
            // Add class if the color scheme is not dark(default)
            if (options.colorScheme != 'light') {
              cal.addClass('colpick_' + options.colorScheme)
            }
            // Setup submit button
            cal.find('div.colpick_submit').html(options.submitText).click(clickSubmit)
            // Setup input fields
            options.fields = cal.find('input').change(change).blur(blur).focus(focus)
            cal.find('span').mousedown(downIncrement).end().find('>div.colpick_current_color').click(restoreOriginal)
            // Setup hue selector
            options.selector = cal.find('div.colpick_color').mousedown(downSelector)
            options.selectorIndic = options.selector.find('div div')
            // Store parts of the plugin
            options.el = this
            options.hue = cal.find('div.colpick_hue div')
            cal.find('div.colpick_hue').mousedown(downHue)
            options.newColor = cal.find('div.colpick_new_color')
            options.currentColor = cal.find('div.colpick_current_color')
            // Store options and fill with default color
            cal.data('colpick', options)
            fillRGBFields(options.color, cal.get(0))
            fillHSBFields(options.color, cal.get(0))
            fillHexFields(options.color, cal.get(0))
            setHue(options.color, cal.get(0))
            setSelector(options.color, cal.get(0))
            setCurrentColor(options.color, cal.get(0))
            setNewColor(options.color, cal.get(0))
            // Append to the body if flat=false, else show in place
            if (options.flat) {
              cal.appendTo(this).show()
              cal.css({
                position: 'relative',
                display: 'block'
              })
            } else {
              cal.appendTo(document.body)
              $(this).on(options.showEvent, show)
              cal.css({
                position: 'absolute'
              })
            }
          }
        })
      },

      // colpickShow
      showPicker: function () {
        return this.each(function () {
          if ($(this).data('colpickId')) {
            show.apply(this)
          }
        })
      },

      // colpickHide
      hidePicker: function () {
        return this.each(function () {
          if ($(this).data('colpickId')) {
            $('#' + $(this).data('colpickId')).hide()
          }
        })
      },

      // colpickSetColor
      setColor: function (col) {
        if (typeof col === 'string') {
          col = HexToHSB(col)
        } else if (col.r != undefined && col.g != undefined && col.b != undefined) {
          col = RGBToHSB(col)
        } else if (col.h != undefined && col.s != undefined && col.b != undefined) {
          col = fixHSB(col)
        } else {
          return this
        }
        return this.each(function () {
          if ($(this).data('colpickId')) {
            var cal = $('#' + $(this).data('colpickId'))
            cal.data('colpick').color = col
            cal.data('colpick').origColor = col
            fillRGBFields(col, cal.get(0))
            fillHSBFields(col, cal.get(0))
            fillHexFields(col, cal.get(0))
            setHue(col, cal.get(0))
            setSelector(col, cal.get(0))
            setCurrentColor(col, cal.get(0))
            setNewColor(col, cal.get(0))
          }
        })
      }
    }
  }())
  $.fn.extend({
    colpick: colpick.init,
    colpickHide: colpick.hidePicker,
    colpickShow: colpick.showPicker,
    colpickSetColor: colpick.setColor
  })
})(jQuery)
